/**
 * @file VideoStream.cpp
 * @brief 执行文件
 * @note
 * 目前仅支持推流一个视频流
 * 配置文件
 * 路径：`/etc/supermatrix/VideoStream.yaml`
 * 示例
 * ```
 * srturl:
 * 'srt://192.168.1.250:10080?streamid=#!::r=live/livestream?secret=6f71279c11654ecf87b2c022fdaabd20,m=publish'
 * IPCHost: '127.0.0.1'
 * IPCPort: '14001
 * ```
 * 广播监听端口：14005
 * @todo
 * 支持多视频推流
 */

#include "../src/VideoStreamIPC.hpp"
#include "Client_types.h"
#include <ClientSub.hpp>
#include <Encoder.hpp>
#include <atomic>
#include <chrono>
#include <spdlog/spdlog.h>
#include <stop_token>
#include <string>
#include <thread>
#include <thrift/TToString.h>
#include <thrift/concurrency/ThreadFactory.h>
#include <thrift/concurrency/ThreadManager.h>
#include <thrift/protocol/TBinaryProtocol.h>
#include <thrift/server/TSimpleServer.h>
#include <thrift/server/TThreadPoolServer.h>
#include <thrift/server/TThreadedServer.h>
#include <thrift/transport/TBufferTransports.h>
#include <thrift/transport/TServerSocket.h>
#include <thrift/transport/TSocket.h>
#include <thrift/transport/TTransportUtils.h>
#include <yaml-cpp/yaml.h>

std::atomic_bool runflag = true;
std::jthread workThread;
std::string selectUUID;
BaseEncoder::ImageType imgStreamType;
long imgWidth, imgHeight;

int main() {
  spdlog::info(">>>>>> Initialize");
  YAML::Node config = YAML::LoadFile("/etc/supermatrix/VideoStream.yaml");
  Encoder encoder(config["srturl"].as<std::string>());
  VideoStreamIPC ipc;
  ipc.Boot(config["IPCHost"].as<std::string>(), config["IPCPort"].as<long>());

  std::vector<std::string> list = ipc.GetRealtimeImageList();
  if (list.size() == 0)
    throw std::runtime_error("Can't find any camera");
  selectUUID = list[0];

  auto StopStreamFunc = [&encoder](const std::string &uuid) {
    if (uuid == selectUUID && workThread.joinable()) {
      workThread.request_stop();
      workThread.join();
      encoder.EndStream();
    }
  };

  ClientSub subscribe;

  subscribe.funcStartShot = [&ipc, &encoder](std::string uuid) {
    spdlog::info("Receive StartShot {}", uuid);
    if (uuid != selectUUID) {
      spdlog::info("UUID unmatch {} , selectUUID is {}", uuid, selectUUID);
      return;
    }
    {
      auto [iWidth, iHeight, iType] = ipc.GetPreviewImageInf(uuid);
      imgWidth = iWidth;
      imgHeight = iHeight;
      switch (iType) {
      case Thrift::ImageFormat::type::GERY:
        imgStreamType = BaseEncoder::ImageType::GREY;
        break;
      case Thrift::ImageFormat::type::RGB8:
        imgStreamType = BaseEncoder::ImageType::RGB8;
        break;
      }
    }
    encoder.StartStream(imgWidth, imgHeight, imgStreamType);
    workThread = std::jthread([&ipc, &encoder](std::stop_token token) {
      long imgsize = imgWidth * imgHeight * []() -> long {
        switch (imgStreamType) {
        case decltype(imgStreamType)::GREY:
          return 1;
          break;
        case decltype(imgStreamType)::RGB8:
          return 3;
          break;
        }
      }();
      unsigned char *imgdata = new unsigned char[imgsize];
      while (!token.stop_requested()) {
        std::this_thread::sleep_for(std::chrono::milliseconds(33));
        ipc.GetRealtimeImage(0, imgdata, imgsize);
        encoder.InputImage(imgdata);
      }
      delete[] imgdata;
    });
  };

  subscribe.funcStopShot = [&StopStreamFunc](const std::string &uuid) {
    spdlog::info("Receive StopShot {}", uuid);
    StopStreamFunc(uuid);
  };

  subscribe.funcMessage = [](const std::string &msg) {
    spdlog::info("Receive Message but not handle : {}", msg);
  };

  subscribe.funcCameraOffline = [&StopStreamFunc](const std::string &uuid) {
    spdlog::info("Receive CameraOffline {}", uuid);
    StopStreamFunc(uuid);
  };

  spdlog::info(">>>>>> Server Ready");
  while (sleep(10) == 0)
    ;
  spdlog::info(">>>>>> Server Exiting");
  StopStreamFunc(selectUUID);
}
